package com.syeet.gulimall.order.config;

import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.retry.MessageRecoverer;
import org.springframework.amqp.rabbit.retry.RepublishMessageRecoverer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 默认重试次数耗尽的消息直接丢弃 (RejectAndDontRequeueRecoverer)
 * 现在将重试次数耗尽的消息放入error.direct交换机(RepublishMessageRecoverer)
 *
 * 什么是死信？
 * 当一个队列中的消息满足下列情况之一时，可以成为死信（dead letter）：
 *
 * - 消费者使用basic.reject或 basic.nack声明消费失败，并且消息的requeue参数设置为false
 * - 消息是一个过期消息，超时无人消费
 * - 要投递的队列消息满了，无法投递
 * 如果这个包含死信的队列配置了`dead-letter-exchange`属性，指定了一个交换机，
 * 那么队列中的死信就会投递到这个交换机中，而这个交换机称为**死信交换机**（Dead Letter Exchange，检查DLX）
 * @author xhl
 * @date 2023/5/9
 */
@Configuration
public class ErrorMessageConfig {

    @Bean
    public DirectExchange errorMessageExchange(){
        return new DirectExchange("error.direct");
    }

    @Bean
    public Queue errorQueue(){
        return new Queue("error.queue");
    }

    @Bean
    public Binding errorMessageBinding(){
        return BindingBuilder.bind(errorQueue()).to(errorMessageExchange()).with("error");
    }

    //覆盖spring消费者重试次数耗尽，就丢弃消息的策略，改为消息失败后进入error.direct交换机，再重新发送到error.queue，处理消息
    @Bean
    public MessageRecoverer republishMessageRecoverer(RabbitTemplate rabbitTemplate){
        return new RepublishMessageRecoverer(rabbitTemplate, "error.direct", "error");
    }

    /* @Bean
    public DirectExchange ttlDirectExchange(){
        return new DirectExchange("ttl.direct");
    }

    //基于ttl与死信交换机实现延迟队列的效果，不推荐
   @Bean
    public Queue ttlQueue(){
        return QueueBuilder
                .durable("ttl.queue")
                .ttl(10000)  //设置队列超时时间10s，若该队列中消息在10s结束后没有被消费者消费，就会被丢弃，丢弃的消息可称为死信
                .deadLetterExchange("dl.direct")//死信被放到死信交换机发送
                .deadLetterRoutingKey("dl")//死信交换机与死信队列的routingkey，就是该案例SpringRabbitListener类listenDlQueue方法声明
                .build();
    }

    @Bean
    public Binding ttlBinding(){
        return BindingBuilder.bind(ttlQueue()).to(ttlDirectExchange()).with("ttl");
    }*/
}
